package com.AUI
{
	import com.AUI.components.*;
	import com.AUI.define.*;
	import com.AUI.define.style.*;
	
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;

	/**
	 * AUI Component Base Class,it's built in box model(as html).
	 * @author HuangMinPing
	 * @site www.AminLab.com
	 */
	public class AComponentBase extends Sprite
	{
		/**
		 * Whether allow align elements.
		 */
		protected var align:Boolean = false;
		/**
		 * HitArea Layer of box model(contains:padding and border area).
		 */
		private var _hitArea:Sprite = new Sprite;
		/**
		 * Content Layer of box model(contains:content area).
		 */
		private var _content:Sprite = new Sprite;
		/**
		 * Elements layer that is contains all elements of component.
		 */
		protected var elements:Sprite = new Sprite;
		/**
		 * Draw style of the component.
		 */
		protected var drawStyle:AComponentStyle = new AComponentStyle;
		/**
		 * Box Model.
		 * @see #initBoxModel()
		 */
		protected var boxModel:ABoxModel = new ABoxModel;
		/**
		 * Constructor.
		 */
		public function AComponentBase()
		{
			_hitArea.mouseEnabled = false;
			_content.mouseEnabled = false;
			elements.mouseEnabled = false;
			
			this.hitArea = _hitArea;
			
			addChild(_hitArea);
			addChild(_content);
			addEventListener(Event.ADDED_TO_STAGE,onAddedToStage);
		}
		/**
		 * @private.
		 */
		protected function onAddedToStage(e:Event):void
		{
			this.removeEventListener(Event.ADDED_TO_STAGE,onAddedToStage);
			_content.addChild(elements);
			AUIPrivate.BD.draw(_content);
		}
		/**
		 * Indicates whether is auto size(auto width or auto height or botth).
		 * @see com.AUI.AStyle#width
		 * @see com.AUI.AStyle#height
		 */
		protected function isAutoSize():Boolean
		{
			return drawStyle.content.width.type == DIM_TYPE.AUTO || drawStyle.content.height.type == DIM_TYPE.AUTO;
		}
		/**
		 * Indicates whether is auto width.
		 * @see com.AUI.AStyle#width
		 */
		protected function isAutoWidth():Boolean
		{
			return drawStyle.content.width.type == DIM_TYPE.AUTO;
		}
		/**
		 * Indicates whether is auto height.
		 * @see com.AUI.AStyle#height
		 */
		protected function isAutoHeight():Boolean
		{
			return drawStyle.content.height.type == DIM_TYPE.AUTO;
		}
		/**
		 * Indicates whether is overflow x(content.width less than elements.width)
		 */
		protected function isOverflowWidth():Boolean
		{
			return elements.width > boxModel.content.width;
		}
		/**
		 * Indicates whether is overflow y(content.height less than elements.height)
		 */
		protected function isOverflowHeight():Boolean
		{
			return elements.height > boxModel.content.height;
		}
		/**
		 * Indicates whether is overflow x(content.width less than elements.width)
		 */
		protected function isOverflowSize():Boolean
		{
			return elements.width > boxModel.content.width && elements.height > boxModel.content.height;
		}
		/**
		 * Call it to reinit box model.
		 * @see #boxes
		 */
		protected function resizeBoxModel():void
		{
			// 1.get baisc information
			var m:EDGES   = drawStyle.margin;
			var b:BORDERS = drawStyle.border;
			var p:EDGES   = drawStyle.padding;
			var PR:int = p.right;
			var PB:int = p.bottom;
			var PL:int = p.left;
			var PT:int = p.top;
			var BR:int = b.right.width;
			var BB:int = b.bottom.width;
			var BL:int = b.left.width;
			var BT:int = b.top.width;
			var MR:int = m.right;
			var MB:int = m.bottom;
			var ML:int = m.left;
			var MT:int = m.top;
			var BX:int = ML;
			var BY:int = MT;
			var PX:int = BX + BL;
			var PY:int = BY + BT;
			var CX:int = PX + PL;
			var CY:int = PY + PT;
			// 2.compute boxes information
			var CW:Number = drawStyle.content.width.type  == DIM_TYPE.AUTO ? elements.width  : drawStyle.content.width.value;
			var CH:Number = drawStyle.content.height.type == DIM_TYPE.AUTO ? elements.height : drawStyle.content.height.value;
			var PW:Number = CW + PL + PR;
			var PH:Number = CH + PT + PB;
			var BW:Number = PW + BL + BR;
			var BH:Number = PH + BT + BB;
			var MW:Number = BW + ML + MR;
			var MH:Number = BH + MT + MB;
			// if size less than 0,then nothing to render
			if(MW < 0){ CW = PW = BW = MW = CX = PX = BX = 0; }
			if(MH < 0){ CH = PH = BH = MH = CY = PY = BY = 0; }
			// 3.update boxes information
			var boxC:Rectangle = boxModel.content
			var boxP:Rectangle = boxModel.padding;
			var boxB:Rectangle = boxModel.border;
			var boxM:Rectangle = boxModel.margin;
			boxM.x = 0;
			boxM.y = 0;
			boxB.x = BX;
			boxB.y = BY;
			boxP.x = PX;
			boxP.y = PY;
			boxC.x = CX;
			boxC.y = CY;
			boxC.width  = CW;
			boxC.height = CH;
			boxP.width  = PW;
			boxP.height = PH;
			boxB.width  = BW;
			boxB.height = BH;
			boxM.width  = MW;
			boxM.height = MH;
		}
		/**
		 * ?.
		 */
		protected function refitBoxModel():void
		{
			if(align == false)
			{
				return;
			}
			var TX:int;
			var TY:int;
			var FW:int = boxModel.content.width;
			var FH:int = boxModel.content.height;
			var TW:int = elements.width;
			var TH:int = elements.height;
			switch(drawStyle.align.h)
			{
				case 0:
					TX =(FW - TW) / 2;
					break;
				case 1:
					TX = FW - TW;
					break;
				default:
					TX = 0;
			}
			switch(drawStyle.align.v)
			{
				case 0:
					TY =(FH - TH) / 2;
					break;
				case 1:
					TY = FH - TH;
					break;
				default:
					TY = 0;
			}
			elements.x = TX;
			elements.y = TY;
		}
		/**
		 * Call it to redraw box model.
		 * @see #boxes
		 */
		protected function redrawBoxModel():void
		{
			// initialize box model
			var boxC:Rectangle = boxModel.content;
			var boxP:Rectangle = boxModel.padding;
			var boxB:Rectangle = boxModel.border;
			var boxM:Rectangle = boxModel.margin;
			var CW:int = boxC.width;
			var CH:int = boxC.height;
			var PW:int = boxP.width;
			var PH:int = boxP.height;
			var BW:int = boxB.width;
			var BH:int = boxB.height;
			var MW:int = boxM.width;
			var MH:int = boxM.height;
			_hitArea.x = boxB.x;
			_hitArea.y = boxB.y;
			_content.x = boxC.x;
			_content.y = boxC.y;
			// 1.draw margin box
			this.graphics.clear();
			//this.graphics.beginFill(0,this is AButton ? 1 : 0);
			this.graphics.beginFill(0,0);
			this.graphics.drawRect(0,0,MW,MH);
			// 2.draw border box
			_hitArea.graphics.clear();
			var cmd:Vector.<int>    = AUIPrivate.CMD;
			var bpt:Vector.<Number> = AUIPrivate.BPT;
			var border:BORDERS = drawStyle.border;
			var BR:int = border.right.width;
			var BB:int = border.bottom.width;
			var BL:int = border.left.width;
			var BT:int = border.top.width;
			if(BL)
			{
				bpt[0] = 0; bpt[1] = 0; bpt[2] = 0; bpt[3] = BH; bpt[4] = BL; bpt[5] = BH - BB; bpt[6] = BL; bpt[7] = BT;
				_hitArea.graphics.beginFill(border.left.color,border.left.alpha);
				_hitArea.graphics.drawPath(cmd,bpt);
			}
			if(BR)
			{
				bpt[0] = BW; bpt[1] = 0; bpt[2] = BW; bpt[3] = BH; bpt[4] = BW - BR; bpt[5] = BH - BB; bpt[6] = BW - BR; bpt[7] = BT;
				_hitArea.graphics.beginFill(border.right.color,border.right.alpha);
				_hitArea.graphics.drawPath(cmd,bpt);
			}
			if(BT)
			{
				bpt[0] = 0; bpt[1] = 0; bpt[2] = BW; bpt[3] = 0; bpt[4] = BW - BR; bpt[5] = BT; bpt[6] = BL; bpt[7] = BT;
				_hitArea.graphics.beginFill(border.top.color,border.top.alpha);
				_hitArea.graphics.drawPath(cmd,bpt);
			}
			if(BB)
			{
				bpt[0] = 0; bpt[1] = BH; bpt[2] = BW; bpt[3] = BH; bpt[4] = BW - BR; bpt[5] = BH - BB; bpt[6] = BL; bpt[7] = BH - BB;
				_hitArea.graphics.beginFill(border.bottom.color,border.bottom.alpha);
				_hitArea.graphics.drawPath(cmd,bpt);
			}
			// 3.draw padding box
			var background:IMAGE = drawStyle.background;
			_hitArea.graphics.beginFill(background.solid.color,background.solid.alpha);
			_hitArea.graphics.drawRect(BL,BT,PW,PH);
			if(background.image)
			{
				var sliceX:int = background.slice.x;
				var sliceY:int = background.slice.y
				var sliceW:int = background.slice.width;
				var sliceH:int = background.slice.height;
				var bmpData:BitmapData = AUIPrivate.sliceBitamp(background.image,PW,PH,sliceX,sliceY,sliceX + sliceW,sliceY + sliceH);
				AUIPrivate.BDM.tx = BL;
				AUIPrivate.BDM.ty = BT;
				_hitArea.graphics.beginBitmapFill(bmpData,AUIPrivate.BDM,background.repeat);
				_hitArea.graphics.drawRect(BL,BT,PW,PH);
			}
			// 4.draw content box
			var CR:Rectangle = _content.scrollRect || (new Rectangle);
			if(CR.width != CW || CR.height != CH)
			{
				CR.x	  = 0;
				CR.y	  = 0;
				CR.width  = CW;
				CR.height = CH;
				_content.scrollRect = CR;
				//AUIPrivate.BD.draw(_content); // fix content width and height immediately.
			}
			// 5.update alpha
			this.alpha = drawStyle.alpha;
		}
		/**
		 * Call it to update box model.
		 * @see #updateStyle()
		 */
		public function updateBoxModel():void
		{
			resizeBoxModel();
			redrawBoxModel();
			refitBoxModel();
		}
		/**
		 * Call it to update the content of box model if it whether need to redraw.
		 */
		public function updateContentBox():void
		{
			var c:Rectangle = this.boxModel.content.clone();
			resizeBoxModel();
			if(c.equals(this.boxModel.content) == false)
			{
				redrawBoxModel();
			}
			refitBoxModel();
		}
	}
}